package com.axinfu.util;

import java.util.Calendar;
import java.util.Date;

/**
 * 工具：重试机制
 *
 * @author ZJN
 * @since 2022/6/15
 */
public class RetryUtil {

    public static final String UNIT_SECOND = "s";
    public static final String UNIT_MINUTE = "m";
    public static final String UNIT_HOUR = "h";
    public static final String UNIT_DAY = "d";
    public static final String STR_BLANK = "";

    private RetryUtil() {
    }

    /**
     * 将字符表示的时间转换为秒数：
     * s秒、m分钟（默认）、h小时、d天（不区分大小写）
     *
     * @param config 字符表示的时间
     * @return 秒数
     */
    public static int convertSeconds(String config) {
        try {
            int s;
            if (config.indexOf(UNIT_SECOND) > 0) {
                s = Integer.parseInt(config.replace(UNIT_SECOND, STR_BLANK));
            } else if (config.indexOf(UNIT_MINUTE) > 0) {
                s = Integer.parseInt(config.replace(UNIT_MINUTE, STR_BLANK)) * 60;
            } else if (config.indexOf(UNIT_HOUR) > 0) {
                s = Integer.parseInt(config.replace(UNIT_HOUR, STR_BLANK)) * 60 * 60;
            } else if (config.indexOf(UNIT_DAY) > 0) {
                s = Integer.parseInt(config.replace(UNIT_DAY, STR_BLANK)) * 24 * 60 * 60;
            } else {
                s = Integer.parseInt(config) * 60;
            }
            return s;
        } catch (Exception e) {
            throw new RuntimeException("表达式格式错误请检查" + config, e);
        }
    }

    /**
     * 计算下次处理时间
     *
     * @param config           格式化配置：时间间隔|次数,多个以逗号隔开，时间可用单位s秒、m分钟（默认）、h小时、d天（不区分大小写）。
     *                         如5s|1,5|5,5d|10表示，每个5秒处理一次处理1次、每隔5分钟处理一次处理5次、每隔5天处理一次处理10次
     * @param workDateTimeLast 最后处理时间，为空是默认为系统当前时间
     * @param workNum          已处理次数，即从未处理过时为0次
     * @return 下次处理时间，返回空表示处理结束
     */
    public static Date calcNext(String config, Date workDateTimeLast, int workNum) {
        try {
            workDateTimeLast = EmptyUtil.isNotEmptyOrDefault(workDateTimeLast, DateUtil.getNow());

            String[] itemConfigs = config.split(",");
            int seconds = Integer.MAX_VALUE;
            int totalNum = 0;
            for (String itemConfig : itemConfigs) {
                if (EmptyUtil.isEmpty(itemConfig)) {
                    continue;
                }

                String[] item = itemConfig.split("\\|");
                if (item.length != 2) {
                    throw new RuntimeException("配置项解释出错" + itemConfig);
                }

                int itemSeconds = convertSeconds(item[0]);
                totalNum += Integer.parseInt(item[1]);

                //超出前面配置的总次数，使用下个配置项
                if (workNum >= totalNum) {
                    continue;
                }

                seconds = itemSeconds;
                break;
            }

            //seconds为初始值，表示未获取到配置或者超出次数
            if (seconds == Integer.MAX_VALUE) {
                return null;
            }

            return DateUtil.dateAdd(workDateTimeLast, Calendar.SECOND, seconds);
        } catch (Exception e) {
            throw new RuntimeException("计算出错，请检查配置格式，" + config, e);
        }
    }

    /**
     * 计算总处理次数
     *
     * @param config 格式化配置：时间间隔|次数,多个以逗号隔开，时间可用单位s秒、m分钟（默认）、h小时、d天（不区分大小写）。
     *               如5s|1,5|5,5d|10表示，每个5秒处理一次处理1次、每隔5分钟处理一次处理5次、每隔5天处理一次处理10次
     * @return 总处理次数
     */
    public static int calcTotalNum(String config) {
        try {
            String[] itemConfigs = config.split(",");
            int totalNum = 0;
            for (String itemConfig : itemConfigs) {
                if (EmptyUtil.isEmpty(itemConfig)) {
                    continue;
                }

                String[] item = itemConfig.split("\\|");
                if (item.length != 2) {
                    throw new RuntimeException("配置项解释出错" + itemConfig);
                }

                totalNum += Integer.parseInt(item[1]);
            }
            return totalNum;
        } catch (Exception e) {
            throw new RuntimeException("计算出错，请检查配置格式，" + config, e);
        }
    }

    /**
     * 计算总处理间隔时间
     *
     * @param config 格式化配置：时间间隔|次数,多个以逗号隔开，时间可用单位s秒、m分钟（默认）、h小时、d天（不区分大小写）。
     *               如5s|1,5|5,5d|10表示，每个5秒处理一次处理1次、每隔5分钟处理一次处理5次、每隔5天处理一次处理10次
     * @return 总处理间隔时间，单位秒
     */
    public static int calcTotalSeconds(String config) {
        try {
            String[] itemConfigs = config.split(",");
            int seconds = 0;
            for (String itemConfig : itemConfigs) {
                if (EmptyUtil.isEmpty(itemConfig)) {
                    continue;
                }

                String[] item = itemConfig.split("\\|");
                if (item.length != 2) {
                    throw new RuntimeException("配置项解释出错" + itemConfig);
                }

                seconds += (convertSeconds(item[0]) * Integer.parseInt(item[1]));
            }
            return seconds;
        } catch (Exception e) {
            throw new RuntimeException("计算出错，请检查配置格式，" + config, e);
        }
    }
}
